package com.muz.spring;

import com.muz.service.AppConfig;

import java.io.File;
import java.io.ObjectStreamException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

public class muzApplicationContext {
    private Class configClass;

    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String,Object> singletonObjects = new ConcurrentHashMap<>();

    public muzApplicationContext(Class configClass) throws ClassNotFoundException {
        this.configClass=configClass;

        //扫描---》beanDefinition-->BeanDefinitionMap
        //是否有注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            //获取注解
            ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            //扫描路径 com.muz.service
            String path = componentScanAnnotation.value();

            //com/muz/service
            path = path.replace(".", "/");

            ClassLoader classLoader = muzApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);

            File file = new File(resource.getFile());

            System.out.println("file:"+file);
            if(file.isDirectory()){
                for (File listFile : file.listFiles()) {
                    String fileName = listFile.getAbsolutePath();
                    String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                    className = className.replace("\\", ".");

                    if(fileName.endsWith(".class")){

                        Class<?> aClass = classLoader.loadClass(className);


                        if (aClass.isAnnotationPresent(Component.class)) {
                            //有就是bean
                            
                            //获得名字
                            Component component = aClass.getAnnotation(Component.class);
                            String beanName = component.value();

                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(aClass);

                            if (aClass.isAnnotationPresent(Scope.class)) {
                                //有scope注解为多例
                                 Scope ScopeAnnotation = aClass.getAnnotation(Scope.class);
                                beanDefinition.setScope(ScopeAnnotation.value());
                            }else {
                                beanDefinition.setScope("singleton");
                            }

                            beanDefinitionMap.put(beanName,beanDefinition);


                        }
                    };
                }

            }

        }

        //扫描完 实例化单例bean
        for (String beanName : beanDefinitionMap.keySet()) {
            if (beanDefinitionMap.get(beanName).getScope().equals("singleton")) {
                Object bean = creatBean(beanName,beanDefinitionMap.get(beanName));
                singletonObjects.put(beanName,bean);
            }
        }
    }

    private Object creatBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getType();
        try {
            Object instance = clazz.getConstructor().newInstance();
            return instance;

        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }


    }

    public Object getBean(String beanName){
        //beanName
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        //不存在
        if(beanDefinition==null){
            throw new NullPointerException();
        }else {
            String scope = beanDefinition.getScope();
            if (scope.equals("singleton")) {
                //单例
                //从单例池拿
                Object bean = singletonObjects.get(beanName);
                //没能拿到，查询创建
                if(bean==null){
                    bean = creatBean(beanName, beanDefinition);
                    singletonObjects.put(beanName,bean);
                }
                return bean;

            }else {
                //多例
                return creatBean(beanName,beanDefinition);
            }

        }
    }
}
